// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Script.Serialization;
using System.Web.UI.HtmlControls;
using System.Drawing;
namespace GridControl
{
    /// <summary>
    /// Control that represents a ExtJs TreePane
    /// </summary>
    [ParseChildren(true)]
    [PersistChildren(false)]
    [ToolboxData("<{0}:TreePane runat=\"server\"></{0}:TreePane>")]
    [ToolboxBitmap(typeof(TreeView))]
  
    public class TreePane : WebControl, INamingContainer,IPostBackEventHandler,ICallbackEventHandler
    {
        
        /// <summary>
        /// GridControlExtender to attach
        /// </summary>
        private TreePaneExtender _extender;
        
        /// <summary>
        /// The columns of the grid
        /// </summary>
        private List<GridControl.TreeNode> _Columns;

        /// <summary>
        /// Move event key.
        /// </summary>
        private static readonly Object NodeMovedKey = new Object();

        /// <summary>
        /// Key for the node edited event
        /// </summary>
        private static readonly Object NodeEditedKey = new Object();

        /// <summary>
        /// Key for the node clicked event
        /// </summary>
        private static readonly Object NodeClickedKey = new Object();

        /// <summary>
        /// Key for the nodechecked event
        /// </summary>
        private static readonly Object NodeCheckedKey = new Object();

        /// <summary>
        /// Key for the contextMenu clicked event
        /// </summary>
        private static readonly Object ContextMenuKey = new Object();

        #region Events
        /// <summary>
        /// Event fired when a context-menu is clicked
        /// </summary>
        public event ContextMenuClickedHandler ContextMenuClicked
        {
            add
            {
                base.Events.AddHandler(ContextMenuKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(ContextMenuKey, value);
            }
        }
        /// <summary>
        /// Event fired when a row is moved
        /// </summary>
        public event TreeEventHandler NodeMoved
        {
            add
            {
                base.Events.AddHandler(NodeMovedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(NodeMovedKey, value);
            }
        }
        /// <summary>
        /// Event fired when a node is edited
        /// </summary>
        public event NodeEditedEventHandler NodeEdited
        {
            add
            {
                base.Events.AddHandler(NodeEditedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(NodeEditedKey, value);
            }
        }
        /// <summary>
        /// Event fired when a node is clicked
        /// </summary>
        public event NodeClickedEventHandler NodeClicked
        {
            add
            {
                base.Events.AddHandler(NodeClickedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(NodeClickedKey, value);
            }
        }
        /// <summary>
        /// Event fired when a node is checked
        /// </summary>
        public event NodeCheckedEventHandler NodeChecked
        {
            add
            {
                base.Events.AddHandler(NodeCheckedKey, value);
            }
            remove
            {
                base.Events.RemoveHandler(NodeCheckedKey, value);
            }
        } 
        #endregion
        /// <summary>
        /// Let ASP.NET know to render a div
        /// </summary>
        public TreePane()
            : base(HtmlTextWriterTag.Div)
        {
        }

        #region Properties
        /// <summary>
        /// true to enable animated expand/collapse
        /// </summary>
        public bool animate
        {
            get
            {
                EnsureChildControls();
                return _extender.animate;
            }
            set
            {
                EnsureChildControls();
                _extender.animate = value;
            }
        }
        /// <summary>
        /// If the tree is rend
        /// </summary>
        public bool CheckBoxTree
        {
            get
            {
                EnsureChildControls();
                return _extender.CheckBoxTree;
            }
            set
            {
                EnsureChildControls();
                _extender.CheckBoxTree = value;
            }

        }
        private Menu _ContextMenu;

        /// <summary>
        /// Gets or sets the context menu.
        /// </summary>
        /// <value>The context menu.</value>
        [Browsable(false),Description("The tree context menu")]
        public Menu ContextMenu
        {
            get { return _ContextMenu; }
            set { _ContextMenu = value; }
        }
        /// <summary>
        /// true to register this container with ScrollManager
        /// </summary>
        public bool containerScroll
        {
            get
            {
                EnsureChildControls();
                return _extender.containerScroll;
            }
            set
            {
                EnsureChildControls();
                _extender.containerScroll = value;
            }
        }
        /// <summary>
        /// True if the tree should only allow append drops (use for trees which are sorted)
        /// </summary>
        public bool ddAppendOnly
        {
            get
            {
                EnsureChildControls();
                return _extender.ddAppendOnly;
            }
            set
            {
                EnsureChildControls();
                _extender.ddAppendOnly = value;
            }
        }
        /// <summary>
        /// The DD group this TreePanel belongs to
        /// </summary>
        public string ddGroup
        {
            get
            {
                EnsureChildControls();
                return _extender.ddGroup;
            }
            set
            {
                EnsureChildControls();
                _extender.ddGroup = value;
            }
        }


        /// <summary>
        /// true to enable drag and drop
        /// </summary>
        public bool enableDD
        {
            get
            {
                EnsureChildControls();
                return _extender.enableDD;
            }
            set
            {
                EnsureChildControls();
                _extender.enableDD = value;
            }
        }
        /// <summary>
        /// true to enable just drag
        /// </summary>
        public bool enableDrag
        {
            get
            {
                EnsureChildControls();
                return _extender.enableDrag;
            }
            set
            {
                EnsureChildControls();
                _extender.enableDrag = value;
            }
        }
        /// <summary>
        /// true to enable just drop
        /// </summary>
        public bool enableDrop
        {
            get
            {
                EnsureChildControls();
                return _extender.enableDrop;
            }
            set
            {
                EnsureChildControls();
                _extender.enableDrop = value;
            }
        }
        /// <summary>
        /// false to disable tree lines (defaults to true)
        /// </summary>
        public bool lines
        {
            get
            {
                EnsureChildControls();
                return _extender.lines;
            }
            set
            {
                EnsureChildControls();
                _extender.lines = value;
            }
        }
        /// <summary>
        /// false to hide the root node (defaults to true)
        /// </summary>
        public bool rootVisible
        {
            get
            {
                EnsureChildControls();
                return _extender.rootVisible;
            }
            set
            {
                EnsureChildControls();
                _extender.rootVisible = value;
            }
        }
        /// <summary>
        /// Name of the page that will load ajax nodes
        /// </summary>
        public string Loader
        {
            get
            {
                EnsureChildControls();
                return _extender.Loader;
            }
            set
            {
                EnsureChildControls();
                _extender.Loader = value;
            }
        }
        /// <summary>
        /// Name of the webserice method to call
        /// </summary>
        public string WebServiceMethod
        {
            get
            {
                EnsureChildControls();
                return _extender.WebServiceMethod;
            }
            set
            {
                EnsureChildControls();
                _extender.WebServiceMethod = value;
            }
        }
        /// <summary>
        /// Path of the webservice
        /// </summary>
        public string WebServicePath
        {
            get
            {
                EnsureChildControls();
                return _extender.WebServicePath;
            }
            set
            {
                EnsureChildControls();
                _extender.WebServicePath = value;
            }
        }
        /// <summary>
        /// If the tree has an editor attached to it
        /// </summary>
        public bool Editable
        {
            get
            {
                EnsureChildControls();
                return _extender.Editable;
            }
            set
            {
                EnsureChildControls();
                _extender.Editable = value;
            }
        }
        /// <summary>
        /// Gets or sets a value indicating whether [auto post back].
        /// </summary>
        /// <value><c>true</c> if [auto post back]; otherwise, <c>false</c>.</value>
        public bool AutoPostBack
        {
            get
            {
                EnsureChildControls();
                return _extender.autoPostBack;
            }
            set
            {
                EnsureChildControls();
                _extender.autoPostBack = value;
            }
        }
        /// <summary>
        /// Gets or sets the tree nodes.
        /// </summary>
        /// <value>The tree nodes.</value>
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public List<GridControl.TreeNode> TreeNodes
        {
            get
            {
                
                if (_Columns == null)
                {
                    _Columns = new List<GridControl.TreeNode>();
                }
                return _Columns;
            }




        }
        /// <summary>
        /// Wrap the Controls collection to always ensure they have
        /// been generated before they're accessed
        /// </summary>
        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        } 
        #endregion
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load"></see> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"></see> object that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            this.Page.ClientScript.GetCallbackEventReference(this, "", "", "");
            
        }
        /// <summary>
        /// Create the child controls
        /// that will be generated for this control
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            // Create the extender
            _extender = new TreePaneExtender();
            _extender.TargetControlID = this.ID;
            _extender.ID = "TreePaneExtender";
         
            if (!this.DesignMode)
                Controls.AddAt(0, _extender);

            // If we already have items in the ViewState, create the control


            ClearChildViewState();
        }

        /// <summary>
        /// Gets the node specified
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public TreeNode GetNodeById(string id)
        {
            foreach (TreeNode n in this._Columns)
            {
                if (n.id==id)
                {
                    return n; 
                }
            }
            return null;
        }
        ///// <summary>
        ///// Removes a node from the tree
        ///// </summary>
        ///// <param name="node"></param>
        //public void RemoveNode(TreeNode node)
        //{
        //    // Force the page to output the postback script
        //    Page.ClientScript.GetPostBackEventReference(this, String.Empty);
        //    // We can't use GetPostBackEvent here because the argument is not a string literal, but a client variable.
        //    Page.ClientScript.RegisterStartupScript(typeof(TreePane), "ServerDelete",
        //        "var res=" + this.ID + "_removeNode();" + ";__doPostBack('" + UniqueID + "',res);", true);
        
        // }
    
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.PreRender"></see> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"></see> object that contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            HttpRequest Request= HttpContext.Current.Request;
            HttpResponse Response = HttpContext.Current.Response;
            if (!string.IsNullOrEmpty(Request["node"]))
            {
                Response.Clear();
                List<TreeNode> nodes = new List<TreeNode>();
                for (int i = 0; i < this._Columns.Count; i++)
                {
                    if (this._Columns[i].parentNodeId==Request["node"])
                    {
                        nodes.Add(this._Columns[i]);
                    }
                }
                JavaScriptSerializer ser= new JavaScriptSerializer();
                Response.Write(ser.Serialize(nodes));
                Response.End();
            }

            string csslink = "<link href='" +
           Page.ClientScript.GetWebResourceUrl(this.GetType(),
         "GridControl.yui-ext.css")
        + "' rel='stylesheet' type='text/css' />";
            LiteralControl include = new LiteralControl(csslink);
            this.Page.Header.Controls.Add(include);
            if (!DesignMode)
            {
                JavaScriptSerializer conv = new JavaScriptSerializer();
                string output = conv.Serialize(this._Columns);
                _extender.TreeNodes = output;
                _extender.ContextMenu = conv.Serialize(this.ContextMenu);
            }
        }





        #region IPostBackEventHandler Members

        /// <summary>
        /// When implemented by a class, enables a server control to process an event raised when a form is posted to the server.
        /// </summary>
        /// <param name="eventArgument">A <see cref="T:System.String"></see> that represents an optional event argument to be passed to the event handler.</param>
        public void RaisePostBackEvent(string eventArgument)
        {
            RaiseCallbackEvent(eventArgument);
        }

        #endregion

        /// <summary>
        /// Raises the context menu clicked event.
        /// </summary>
        /// <param name="e">The <see cref="T:GridControl.TreeContextMenuEventArgs"/> instance containing the event data.</param>
        protected virtual void OnContextMenuClicked(TreeContextMenuEventArgs e)
        {
            ContextMenuClickedHandler eventHandler = (ContextMenuClickedHandler)base.Events[ContextMenuKey];
            if (eventHandler != null)
            {
                eventHandler(this, e);
            }
        }
        /// <summary>
        /// Raises the node moved event.
        /// </summary>
        /// <param name="e">The <see cref="T:GridControl.NodeMoveEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNodeMoved(NodeMoveEventArgs e)
        {
            TreeEventHandler eventHandler = (TreeEventHandler)base.Events[NodeMovedKey];
            if (eventHandler != null)
            {
                eventHandler(this, e);
            }
        }
        /// <summary>
        /// Raises the node edited event.
        /// </summary>
        /// <param name="e">The <see cref="T:GridControl.NodeEditedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNodeEdited(NodeEditedEventArgs e)
        {
            NodeEditedEventHandler eventHandler = (NodeEditedEventHandler)base.Events[NodeEditedKey];
            if (eventHandler != null)
            {
                eventHandler(this, e);
            }
        }
        /// <summary>
        /// Raises the node clicked event.
        /// </summary>
        /// <param name="e">The <see cref="T:GridControl.NodeClickedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNodeClicked(NodeClickedEventArgs e)
        {
            NodeClickedEventHandler eventHandler = (NodeClickedEventHandler)base.Events[NodeClickedKey];
            if (eventHandler != null)
            {
                eventHandler(this, e);
            }
        }
        /// <summary>
        /// Raises the node checked event.
        /// </summary>
        /// <param name="e">The <see cref="T:GridControl.NodeClickedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnNodeChecked(NodeCheckedEventArgs e)
        {
            NodeCheckedEventHandler eventHandler = (NodeCheckedEventHandler)base.Events[NodeCheckedKey];
            if (eventHandler != null)
            {
                eventHandler(this, e);
            }
        }
        #region ICallbackEventHandler Members

        /// <summary>
        /// Returns the results of a callback event that targets a control.
        /// </summary>
        /// <returns>The result of the callback.</returns>
        public string GetCallbackResult()
        {
            return null;
        }

        /// <summary>
        /// Processes a callback event that targets a control.
        /// </summary>
        /// <param name="eventArgument">A string that represents an event argument to pass to the event handler.</param>
        public void RaiseCallbackEvent(string eventArgument)
        {
            JavaScriptSerializer jsSerialiser = new JavaScriptSerializer();
            TreeEventArgs eventArgs = jsSerialiser.Deserialize<TreeEventArgs>(eventArgument);
            switch (eventArgs.EventName.ToLower())
            {
                case "nodemoved":
                    OnNodeMoved(jsSerialiser.Deserialize<NodeMoveEventArgs>(eventArgs.Arguments));
                    break;
                case "nodeedited":
                    OnNodeEdited(jsSerialiser.Deserialize<NodeEditedEventArgs>(eventArgs.Arguments));
                    break;
                case "nodeclicked":
                    OnNodeClicked(jsSerialiser.Deserialize<NodeClickedEventArgs>(eventArgs.Arguments));
                    break;
                case "nodechecked":
                    OnNodeChecked(jsSerialiser.Deserialize<NodeCheckedEventArgs>(eventArgs.Arguments));
                    break;
                case "contextmenuclicked":
                    OnContextMenuClicked(jsSerialiser.Deserialize<TreeContextMenuEventArgs>(eventArgs.Arguments));
                    break;
                default:
                    //Do nothing
                    break;
            }
        }

        #endregion
    }
}